﻿///////////////////////////////////////////////////////////
//  ContextMenuItem.cs
//  Implementation of the Class ContextMenuItem
//  Created on:      30-jul-2008 21:35
//  Original author: POliveira.7Comm
///////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.ComponentModel;
using System.Windows.Controls;
using PSE.Framework.UI.Controls.SmartClient.Validation;
using System.Collections.ObjectModel;
using System.Windows.Threading;
 
namespace PSE.Framework.UI.Controls.SmartClient
{
    /// <summary>
    /// Componente de exibição dos itens do menu contextual
    /// </summary>
    [DefaultProperty("Header")]
    public class ContextMenuItem : MenuItem, IValidatableObject
    {
        #region Construtors
        public ContextMenuItem()
        {
            UpdateIcon();
        }

        protected override void OnVisualParentChanged(DependencyObject oldParent)
        {
            base.OnVisualParentChanged(oldParent);
            ValidationManager.InitializeValidation(this);
        }

        static ContextMenuItem()
        {
            IsEnabledProperty.OverrideMetadata(typeof(ContextMenuItem), new FrameworkPropertyMetadata(OnIsEnabledChanged));
        }
        #endregion

        #region IValidatable Members

        public static readonly DependencyProperty CanValidateProperty = ValidationManager.CanValidateProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Indica se o objeto suporta validação
        /// </summary>
        public bool CanValidate
        {
            get { return (bool)GetValue(CanValidateProperty); }
        }

        public static readonly DependencyProperty ValidationGroupProperty = ValidationManager.ValidationGroupProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Grupo de validação do objeto, informar null ou string.Empty nos objetos que disparam 
        /// validação para ignorar o grupo de validação
        /// </summary>
        public string ValidationGroup
        {
            get { return (string)GetValue(ValidationGroupProperty); }
            set { SetValue(ValidationGroupProperty, value); }
        }

        #endregion

        #region IValidatableObject Members

        public static readonly DependencyProperty ClearServiceErrorsProperty = ValidationManager.ClearServiceErrorsProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Indica se o objeto dispara validação
        /// </summary>
        public bool ClearServiceErrors
        {
            get { return (bool)GetValue(ClearServiceErrorsProperty); }
            set { SetValue(ClearServiceErrorsProperty, value); }
        }

        public static readonly DependencyProperty CausesValidationProperty = ValidationManager.CausesValidationProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Indica se o objeto dispara validação
        /// </summary>
        public bool CausesValidation
        {
            get { return (bool)GetValue(CausesValidationProperty); }
            set { SetValue(CausesValidationProperty, value); }
        }

        public static readonly DependencyProperty ValidationTriggersProperty = ValidationManager.ValidationTriggersProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Triggers que disparam a validação do objeto
        /// </summary>
        public ValidationTriggerCollection ValidationTriggers
        {
            get { return (ValidationTriggerCollection)GetValue(ValidationTriggersProperty); }
        }

        public static readonly DependencyProperty ValidationRulesProperty = ValidationManager.ValidationRulesProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Regras de validação do objeto
        /// </summary>
        public ValidationRuleCollection ValidationRules
        {
            get { return (ValidationRuleCollection)GetValue(ValidationRulesProperty); }
        }

        public static readonly DependencyProperty HasErrorProperty = ValidationManager.HasErrorProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Indica se objeto tem erros
        /// </summary>
        public bool HasError
        {
            get { return (bool)GetValue(HasErrorProperty); }
        }

        public static readonly DependencyProperty ErrorsProperty = ValidationManager.ErrorsProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Erros do objeto
        /// </summary>
        public ReadOnlyObservableCollection<ValidationError> Errors
        {
            get { return (ReadOnlyObservableCollection<ValidationError>)GetValue(ErrorsProperty); }
        }

        public static readonly DependencyProperty ErrorTemplateProperty = ValidationManager.ErrorTemplateProperty.AddOwner(typeof(ContextMenuItem));
        /// <summary>
        /// Template aplicado quando objeto tem erros
        /// </summary>
        public ControlTemplate ErrorTemplate
        {
            get { return (ControlTemplate)GetValue(ErrorTemplateProperty); }
            set { SetValue(ErrorTemplateProperty, value); }
        }

        /// <summary>
        /// Valida todas as properties do objeto
        /// </summary>
        /// <returns>True se todas as properties forem válidas</returns>
        public bool Validate()
        {
            return ValidationManager.Validate(this);
        }

        /// <summary>
        /// Valida a property informada do objeto
        /// </summary>
        /// <param name="property">Property a ser validada</param>
        /// <returns>True se a property for válida</returns>
        public bool Validate(DependencyProperty property)
        {
            return ValidationManager.Validate(this, property);
        }

        /// <summary>
        /// Valida todos os objetos do container pai do objeto
        /// </summary>
        /// <returns>True se todos os objetos forem válidos</returns>
        public bool ValidateParentContainer()
        {
            return ValidationManager.ValidateParentContainer(this);
        }

        #endregion

        #region Propriedades
        /// <summary>
        /// Propriedade que receberá o nome do DrawingBrush a ser utilizado como ícone do item do menu.
        /// A propriedade não deve ser utilizada pela tela porque haverá controle automático de ícones
        /// desabilitados
        /// </summary>
        public static readonly DependencyProperty ContextMenuItemIconProperty = DependencyProperty.Register("ContextMenuItemIcon", typeof(string), typeof(ContextMenuItem), new FrameworkPropertyMetadata("IconContextMenuNone", OnContextMenuItemIconChanged));

        public string ContextMenuItemIcon
        {
            get { return (string)GetValue(ContextMenuItemIconProperty); }
            set { SetValue(ContextMenuItemIconProperty, value); }
        }
        #endregion

        #region Métodos Estáticos
        private static void OnContextMenuItemIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(d))
                return;

            ContextMenuItem instance = d as ContextMenuItem;
            if (instance != null)
            {
                if (instance.ContextMenuItemIcon != null)
                {
                    instance.UpdateIcon();
                }
            }
        }

        private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(d))
                return;

            ContextMenuItem instance = d as ContextMenuItem;
            if (instance != null)
            {
                if (instance.ContextMenuItemIcon != null)
                {
                    instance.UpdateIcon();
                }
            }
        }
        #endregion

        #region Métodos Privados
        /// <summary>
        /// Método que verifica qual ícone deve ser exibido (normal ou desabilitado)
        /// Na criação dos ícones ambos serã desenvolvidos e o controle será automático pelo controle
        /// </summary>
        protected void UpdateIcon()
        {
            ///Método alterado de forma a criar uma Image para atribuir ao icone do Item de menu contextual
            ///Teve de ser feito dessa forma, pois aparentemente há um bug no componente WPF que impede que o objeto
            ///seja removido da memória pelo GC caso tenha um ícone setado vida SetResourceReference (DynamicResource)
            Image icon = new Image();
            if (this.IsEnabled)
            {                
                icon.SetResourceReference(Image.SourceProperty, this.ContextMenuItemIcon);
            }
            else
            {
                icon.SetResourceReference(Image.SourceProperty, this.ContextMenuItemIcon + "Disabled");
            }
            this.Icon = icon;
        }
        #endregion

        protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
        {
            base.OnMouseEnter(e);

            if (this.Items.Count > 0)
            {
                DispatcherTimer timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromMilliseconds((double)SystemParameters.MenuShowDelay);
                timer.Tick += new EventHandler(
                    delegate(object sender, EventArgs args)
                    {
                        this.IsSubmenuOpen = true;
                        ((DispatcherTimer)sender).Stop();
                    }
                );
                timer.Start();
            }
        }

        protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
        {
            base.OnMouseLeave(e);

            if (this.Items.Count > 0)
            {
                DispatcherTimer timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromMilliseconds((double)SystemParameters.MenuShowDelay);
                timer.Tick += new EventHandler(
                    delegate(object sender, EventArgs args)
                    {
                        this.IsSubmenuOpen = false;
                        ((DispatcherTimer)sender).Stop();
                    }
                );
                timer.Start();
            }
        }

        /// <summary>
        /// Recupera o container de validacao ao qual o item esta associado
        /// </summary>
        /// <returns></returns>
        internal IValidatableContainer GetValidatableContainer()
        {
            ContextMenu parent = ControlHelper.FindParent(this, typeof(ContextMenu)) as ContextMenu;
            if (parent != null)
            {
                if (parent.PlacementTarget != null)
                    return ControlHelper.FindParent(parent.PlacementTarget, typeof(IValidatableContainer)) as IValidatableContainer;
            }

            return null;
        }

        /// <summary>
        /// Componente de exibição dos subitens
        /// </summary>
        protected override System.Windows.DependencyObject GetContainerForItemOverride()
        {
            return new ContextMenuItem();
        }
    }
}
